﻿\subsection{装载引导加载器}

本设计中，引导加载器需要被装载到内存 \lstinline{0:0x600} \TO \lstinline{0:0xDFF} 位置。
主引导记录需要通过读取磁盘，将磁盘中的引导加载器装载到该内存空间。
BIOS 提供了用于读取磁盘的 \lstinline{0x13} 号中断（表 \ref{BIOS_RESET_DISK}），该中断服务对磁盘设备接口进行了简易封装，并提供了重置、读磁盘、写磁盘等子功能。
主引导记录读取磁盘可通过调用 BIOS 中断实现。

\lstinline{0x00} 号子功能可用于重置磁盘，当读写磁盘出现错误时，可在重置磁盘后再次尝试读写操作。

\begin{figure}[h!]
\captionsetup{type=table}
\caption{BIOS 中断——重置磁盘}
\label{BIOS_RESET_DISK}
\begin{minipage}{14cm}
    \Centering
    \begin{tabular}{|>{\RaggedRight\arraybackslash\small}p{10cm}|}
        \hline
        \Centering\textbf{BIOS 中断——重置磁盘}\\
        \hline
        描述：重置磁盘 \\
        中断号：\verb{0x13}\\
        功能号：\verb{0x00}\\
        \hline
        \textbf{输入}\\
        \quad{}\verb{AH} = \verb{00H}\\
        \quad{}\verb{DL} = 设备编号 \\
        \hline
        \textbf{输出}\\
        \quad{}\verb{EFLAGS.CF} = \verb{0} 成功 \\
        \quad{}\verb{EFLAGS.CF} = \verb{1} 出错 \\
        \hline
        注：\\
        （1） 对于硬盘设备，可取 \verb{0x80} 或 \verb{0x81}，分别代表主硬盘（Master Hard Disk）和从硬盘（Slave Hard Disk）。\\
        \hline
    \end{tabular}
\end{minipage}
\end{figure}

\lstinline{0x02} 号子功能可用于读取磁盘（表 \ref{BIOS_READ_DISK}）。
由于本操作系统采用硬盘作为存储设备，因此在调用 BIOS 读磁盘功能时需要指定设备类型为硬盘。
BIOS 读磁盘中断采用 CHS （Cylinder-Header-Sector） 方式为磁盘扇区编址，其中扇区号从 1 开始计数，柱面号和磁头号从 0 开始计数。
将磁盘数据读入内存时需要指定数据存放的内存地址，内存地址由段地址（保存在 \lstinline{ES} 寄存器中）和有效地址（或称偏移地址，保存在 \lstinline{BX} 寄存器中）两部分组成。

\begin{figure}[h!]
\captionsetup{type=table}
\caption{BIOS 中断——读取磁盘}
\label{BIOS_READ_DISK}
\begin{minipage}{14cm}
    \Centering
    \begin{tabular}{|>{\RaggedRight\arraybackslash\small}p{10cm}|}
        \hline
        \Centering\textbf{BIOS 中断——读取磁盘}\\
        \hline
        描述：读取磁盘 \\
        中断号：\verb{0x13}\\ 
        功能号：\verb{0x02}\\
        \hline
        \textbf{输入}\\
        \quad{}\verb{AH} = \verb{0x02}\\
        \quad{}\verb{AL} = 需要读取的磁盘扇区数 \\
        \quad{}\verb{BX} = 缓冲区偏移量 \\
        \quad{}\verb{CH} = 柱面号 \\
        \quad{}\verb{CL} = 扇区号 \\
        \quad{}\verb{DH} = 磁头号 \\
        \quad{}\verb{DL} = 设备编号 \\
        \quad{}\verb{ES} = 缓冲区所在的段地址 \\
        \hline
        \textbf{输出}\\
        \quad{}\verb{EFLAGS.CF} = \verb{0} 读取成功 \\
        \quad{}\verb{EFLAGS.CF} = \verb{1} 读取失败 \\
        \quad{}\verb{AH} = 读取失败对应的错误代码 \\
        \hline
    \end{tabular}
\end{minipage}
\end{figure}

虽然 BIOS 磁盘中断读磁盘子功能允许一次连续读入多个扇区，但是如果连续读取过程中某个扇区读取失败，则必须重新从头开始再次尝试读入。
因此，更为稳妥的做法是每次只读入一个扇区，然后检查进位标志确定当前扇区读取是否成功，如果读取失败，则在重置磁盘后再次尝试（表 \ref{MBR_LOAD_BOOTLOADER}）。

\begin{figure}[h!]
    \Centering
    \caption{使用 BIOS 中断服务装载引导加载器}
    \label{MBR_LOAD_BOOTLOADER}
    \includegraphics[scale=0.75]{build/Paper/Assets/MBR-Reads-BootLoader-Using-BIOS-Interupts.pdf}
\end{figure}

实际的引导加载器一般不会占用太多的扇区数量，因此可据引导加载器预估大小确定主引导记录最终需要读入多少扇区。
用于引导本操作系统的引导加载器整体大小不超过 2048 Bytes，即不超过 4 个扇区，加载到物理地址 \lstinline{0x600 ~ 0xDFF} 范围内。
有效的主引导记录分区必须以魔数 \lstinline{0x55 0xAA} 结尾。
主引导记录将引导加载器调入内存后，通过一条跳转指令跳转至引导加载器起始地址执行。

\begin{minted}[breaklines, breakautoindent=true]{nasm}
jmp 0x0000:0x0600 ; 引导加载器内存起始地址
times (SECTOR_SIZE - ($ - $$) - 2) db 0 ; ($ - $$) 表示当前段已经写入的字节数，末尾两个字节固定
db 0x55, 0xaa
\end{minted}

至此，主引导记录就完成了第一棒的顺利交接。
